package com.meituan.catering.management.order.biz.validator;

import com.meituan.catering.management.common.exception.BizException;
import com.meituan.catering.management.common.model.enumeration.ErrorCode;
import com.meituan.catering.management.order.api.http.model.enumeration.CateringOrderStatusEnum;
import com.meituan.catering.management.order.api.http.model.request.*;
import com.meituan.catering.management.order.dao.mapper.CateringOrderItemAccessoryMapper;
import com.meituan.catering.management.order.dao.mapper.CateringOrderItemMapper;
import com.meituan.catering.management.order.dao.mapper.CateringOrderMapper;
import com.meituan.catering.management.order.dao.model.CateringOrderDO;
import com.meituan.catering.management.order.dao.model.CateringOrderItemAccessoryDO;
import com.meituan.catering.management.order.dao.model.CateringOrderItemDO;
import com.meituan.catering.management.order.remote.ProductRemoteService;
import com.meituan.catering.management.order.remote.ShopRemoteService;
import com.meituan.catering.management.order.remote.model.response.ProductDetailRemoteResponse;
import com.meituan.catering.management.order.remote.model.response.ShopDetailRemoteResponse;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Believe
 * Date 2022/5/27 9:48
 */
@Component
public class OrderControllerServiceValidator {

    @Resource
    private ShopRemoteService shopRemoteService;

    @Resource
    private ProductRemoteService productRemoteService;

    @Resource
    private CateringOrderMapper cateringOrderMapper;

    @Resource
    private CateringOrderItemMapper cateringOrderItemMapper;

    @Resource
    private CateringOrderItemAccessoryMapper cateringOrderItemAccessoryMapper;


    public void searchForPageValid(Long tenantId, Long userId, SearchCateringOrderHttpRequest searchCateringOrderHttpRequest) throws BizException {
        paramValid(tenantId, userId, searchCateringOrderHttpRequest);
    }

    public void findByIdValid(Long tenantId, Long userId, Long orderId) throws BizException {
        paramValid(tenantId, userId, orderId);
    }

    public void placeValid(Long tenantId, Long userId, PlaceCateringOrderHttpRequest request) throws BizException {
        paramValid(tenantId, userId, request);
        infoPlaceValid(tenantId, userId, request);
    }

    public void prepareValid(Long tenantId, Long userId, Long orderId, PrepareCateringOrderHttpRequest request) throws BizException {
        paramValid(tenantId, userId, orderId, request);
        InfoPrepareValid(tenantId, userId, orderId, request);
    }

    public void produceValid(Long tenantId, Long userId, Long orderId, ProduceCateringOrderHttpRequest request) throws BizException {
        paramValid(tenantId, userId, orderId, request);
        infoProduceValid(tenantId, userId, orderId, request);
    }

    public void adjustValid(Long tenantId, Long userId, Long orderId, AdjustCateringOrderHttpRequest request) throws BizException {
        paramValid(tenantId, userId, orderId, request);
        adjustInfoValid(tenantId, userId, orderId, request);
    }

    private void adjustInfoValid(Long tenantId, Long userId, Long orderId, AdjustCateringOrderHttpRequest request) throws BizException {
//        CateringOrderDO cateringOrderDO = cateringOrderMapper.findById(tenantId, userId, orderId);
//        List<CateringOrderItemDO> cateringOrderItemDOList = cateringOrderItemMapper.findById(tenantId, orderId);
//        Set<Long> validIds = CateringOrderUtils.getItemDOIds(cateringOrderItemDOList);
//        List<CateringOrderItemAccessoryDO> accessoryDOList = cateringOrderItemAccessoryMapper.findById(tenantId, validIds);
//        if (!cateringOrderDO.getVersion().equals(request.getVersion())) {
//            throw new BizException(ErrorCode.VERSION_ERROR);
//        }
//        if (cateringOrderDO.getStatus().equals(CateringOrderStatusEnum.BILLED)) {
//            throw new BizException(ErrorCode.STATUS_ERROR);
//        }
//        List<AdjustCateringOrderHttpRequest.Item> items = request.getItems();
//        for (int i = 0; i < items.size(); i++) {
//            if (items.get(i).getVersion() != null) {
//                if (!items.get(i).getVersion().equals(cateringOrderItemDOList.get(i).getVersion())) {
//                    throw new BizException(ErrorCode.VERSION_ERROR);
//                }
//                if (items.get(i).getQuantityOnAdjustment().compareTo(cateringOrderItemDOList.get(i).getPlaceQuantity()) == 1) {
//                    throw new BizException(ErrorCode.QUANTITY_ERROR);
//                }
//            }
//            for (AdjustCateringOrderHttpRequest.Item.Accessory accessory : items.get(i).getAccessories()) {
//                if (accessory.getProductAccessoryId().equals(accessoryDOList.get(i).getProductAccessoryId())) {
//                    if (!accessory.getVersion().equals(accessoryDOList.get(i).getVersion())) {
//                        throw new BizException(ErrorCode.VERSION_ERROR);
//                    }
//                    if (accessory.getQuantityOnAdjustment().compareTo(accessoryDOList.get(i).getPlaceQuantity()) == 1) {
//                        throw new BizException(ErrorCode.QUANTITY_ERROR);
//                    }
//                }
//            }
//        }
    }

    public void billValid(Long tenantId, Long userId, Long orderId, BillCateringOrderHttpRequest request) throws BizException {
        paramValid(tenantId, userId, orderId, request);
        billInfoValid(tenantId, userId, orderId, request);
    }

    private void billInfoValid(Long tenantId, Long userId, Long orderId, BillCateringOrderHttpRequest request) throws BizException {
        CateringOrderDO cateringOrderDO = cateringOrderMapper.findById(tenantId, userId, orderId);
        if (Objects.isNull(cateringOrderDO)) {
            throw null;
        }
        if (!cateringOrderDO.getVersion().equals(request.getVersion())) {
            throw new BizException(ErrorCode.VERSION_ERROR);
        }
        if (!cateringOrderDO.getTotalPrice().equals(request.getPaid())) {
            throw new BizException(ErrorCode.PAID_ERROR);
        }
        if (cateringOrderDO.getTotalPrice().compareTo(request.getPromotion()) == -1) {
            throw new BizException(ErrorCode.PROMOTION_ERROR);
        }
        if (!cateringOrderDO.getStatus().equals(CateringOrderStatusEnum.PREPARED)) {
            throw new BizException(ErrorCode.STATUS_ERROR);
        }
    }

    private void infoProduceValid(Long tenantId, Long userId, Long orderId, ProduceCateringOrderHttpRequest request) throws BizException {
        CateringOrderDO cateringOrderDO = cateringOrderMapper.findById(tenantId, userId, orderId);
        //订单子项分组
        List<CateringOrderItemDO> cateringOrderItemDOList = cateringOrderItemMapper.findById(tenantId, orderId);
        Set<Long> validProductIds = cateringOrderItemDOList.stream().map(CateringOrderItemDO::getId).collect(Collectors.toSet());
        Map<String, CateringOrderItemDO> orderItemDOMap = cateringOrderItemDOList
                .stream().collect(Collectors.toMap(CateringOrderItemDO::getSeqNo, item -> item));
        //加料分组
        List<CateringOrderItemAccessoryDO> accessoryDOList = cateringOrderItemAccessoryMapper.findById(tenantId, validProductIds);
        Map<String, CateringOrderItemAccessoryDO> accessoryDOMap = accessoryDOList.stream()
                .collect(Collectors.toMap(CateringOrderItemAccessoryDO::getSeqNo, item -> item));
        List<ProduceCateringOrderHttpRequest.Item> items = request.getItems();

        if (!cateringOrderDO.getVersion().equals(request.getVersion())) {
            throw new BizException(ErrorCode.VERSION_ERROR);
        }
        if (!cateringOrderDO.getStatus().equals(CateringOrderStatusEnum.PREPARING)) {
            throw new BizException(ErrorCode.STATUS_ERROR);
        }

        for (ProduceCateringOrderHttpRequest.Item item : items) {
            if (orderItemDOMap.containsKey(item.getSeqNo())) {
                CateringOrderItemDO orderItemDO = orderItemDOMap.get(item.getSeqNo());
                if (!item.getVersion().equals(orderItemDO.getVersion())) {
                    throw new BizException(ErrorCode.VERSION_ERROR);
                }
                if (item.getQuantityOnProduce().compareTo(orderItemDO.getPlaceQuantity()) == 1) {
                    throw new BizException(ErrorCode.QUANTITY_ERROR);
                }
            }
            for (ProduceCateringOrderHttpRequest.Item.Accessory accessory : item.getAccessories()) {
                if (accessoryDOMap.containsKey(accessory.getSeqNo())) {
                    CateringOrderItemAccessoryDO accessoryDO = accessoryDOMap.get(accessory.getSeqNo());
                    if (!accessory.getVersion().equals(accessoryDO.getVersion())) {
                        throw new BizException(ErrorCode.VERSION_ERROR);
                    }
                    if (accessory.getQuantityOnProduce().compareTo(accessoryDO.getPlaceQuantity()) == 1) {
                        throw new BizException(ErrorCode.QUANTITY_ERROR);
                    }
                }
            }
        }
    }

    private void InfoPrepareValid(Long tenantId, Long userId, Long orderId, PrepareCateringOrderHttpRequest request) throws BizException {
        CateringOrderDO cateringOrderDO = cateringOrderMapper.findById(tenantId, userId, orderId);
        List<CateringOrderItemDO> cateringOrderItemDOList = cateringOrderItemMapper.findById(tenantId, orderId);
        Map<String, CateringOrderItemDO> orderItemDOMap = cateringOrderItemDOList.stream()
                .collect(Collectors.toMap(CateringOrderItemDO::getSeqNo, item -> item));
        if (!cateringOrderDO.getVersion().equals(request.getVersion())) {
            throw new BizException(ErrorCode.VERSION_ERROR);
        }
        List<PrepareCateringOrderHttpRequest.Item> items = request.getItems();
        for (PrepareCateringOrderHttpRequest.Item item : items) {
            if (orderItemDOMap.containsKey(item.getSeqNo())) {
                CateringOrderItemDO orderItemDO = orderItemDOMap.get(item.getSeqNo());
                if (!item.getVersion().equals(orderItemDO.getVersion())) {
                    throw new BizException(ErrorCode.VERSION_ERROR);
                }
            }
        }
    }

    private void paramValid(Long tenantId, Long userId, Long orderId, Object request) throws BizException {
        if (tenantId < 0 || userId < 0 || orderId < 0 || request == null) {
            throw new BizException(ErrorCode.PARAM_ERROR);
        }
    }

    private void paramValid(Long tenantId, Long userId, Object request) throws BizException {
        if (tenantId < 0 || userId < 0 || request == null) {
            throw new BizException(ErrorCode.PARAM_ERROR);
        }
    }

    private void infoPlaceValid(Long tenantId, Long userId, PlaceCateringOrderHttpRequest request) throws BizException {
        ShopDetailRemoteResponse shop = shopRemoteService.findByBusinessNo(tenantId, userId, request.getShopBusinessNo());
        Set<Long> httpProductIds = request.getItems().stream()
                .map(PlaceCateringOrderHttpRequest.Item::getProductId).collect(Collectors.toSet());
        List<CateringOrderDO> cateringOrderDOS = cateringOrderMapper.selectAll(tenantId, userId);
        List<ProductDetailRemoteResponse> remoteResponses = productRemoteService.findByIds(tenantId, userId, httpProductIds);
        Map<Long, ProductDetailRemoteResponse> responseMap = remoteResponses.stream()
                .collect(Collectors.toMap(ProductDetailRemoteResponse::getId, item -> item));
        boolean tableNoValid = cateringOrderDOS.stream().anyMatch(item -> item.getTableNo().equals(request.getTableNo()));
        if (tableNoValid) {
            throw new BizException(ErrorCode.TABLE_NO_ERROR);
        }
        for (PlaceCateringOrderHttpRequest.Item item : request.getItems()) {
            if (!responseMap.containsKey(item.getProductId())) {
                throw new BizException(ErrorCode.PRODUCT_ERROR);
            }
            ProductDetailRemoteResponse productDetailRemoteResponse = responseMap.get(item.getProductId());
            if (!productDetailRemoteResponse.getEnabled()) {
                throw new BizException(ErrorCode.DISABLE_ERROR);
            }
        }
        if (!request.getShopBusinessNo().equals(shop.getBusinessNo())) {
            throw new BizException(ErrorCode.SHOP_ERROR);
        }
        if (!shop.getEnabled()) {
            throw new BizException(ErrorCode.DISABLE_ERROR);
        }
    }

    private void paramValid(Long tenantId, Long userId, Long orderId) throws BizException {
        if (tenantId < 0 || userId < 0 || orderId < 0) {
            throw new BizException(ErrorCode.PARAM_ERROR);
        }
    }
}
